package com.doeis.core.db.transaction;

import java.sql.Connection;
import java.sql.Savepoint;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class TransactionSynchronizer {
	private static Map<String, ThreadLocal<Connection>> resources = new HashMap<String, ThreadLocal<Connection>>();
	private static Map<String, ThreadLocal<List<Transaction>>> transactions = new HashMap<String, ThreadLocal<List<Transaction>>>();
	private static Map<String, ThreadLocal<List<Savepoint>>> savepoints = new HashMap<String, ThreadLocal<List<Savepoint>>>();

	public static void initDataSource(String dataSourceName) {
		if (resources.get(dataSourceName) == null) {
			resources.put(dataSourceName, new ThreadLocal<Connection>());
		}

		if (transactions.get(dataSourceName) == null) {
			transactions.put(dataSourceName, new ThreadLocal<List<Transaction>>());
		}

		if (savepoints.get(dataSourceName) == null)
			savepoints.put(dataSourceName, new ThreadLocal<List<Savepoint>>());
	}

	public static Connection getConnectionResource(String datasourceName) {
		ThreadLocal<Connection> localConnections = (ThreadLocal<Connection>) resources.get(datasourceName);
		if (localConnections != null)
			return (Connection) localConnections.get();
		return null;
	}

	public static void bindConnectionResource(String datasourceName, Connection holder) {
		ThreadLocal<Connection> localConnections = (ThreadLocal<Connection>) resources.get(datasourceName);
		if (localConnections != null)
			localConnections.set(holder);
	}

	public static void unbindConnectionResource(String datasourceName) {
		ThreadLocal<Connection> localConnections = (ThreadLocal<Connection>) resources.get(datasourceName);
		if (localConnections != null) {
			localConnections.remove();
			if (hasTransaction(datasourceName))
				localConnections.remove();
		}
	}

	public static void addTransaction(String datasourceName, Transaction transaction) {
		ThreadLocal<List<Transaction>> localTranscactions = (ThreadLocal<List<Transaction>>) transactions.get(datasourceName);
		if (localTranscactions != null) {
			List<Transaction> trxs = (List<Transaction>) localTranscactions.get();
			if (trxs == null) {
				trxs = new ArrayList<Transaction>();
				localTranscactions.set(trxs);
			}
			trxs.add(transaction);
		}
	}

	public static void removeTransaction(String datasourceName, Transaction transaction) {
		ThreadLocal<List<Transaction>> localTranscactions = (ThreadLocal<List<Transaction>>) transactions.get(datasourceName);
		if (localTranscactions != null) {
			List<Transaction> trxs = (List<Transaction>) localTranscactions.get();
			if (trxs == null)
				return;
			trxs.remove(transaction);
		}
	}

	public static boolean hasTransaction(String datasourceName) {
		ThreadLocal<List<Transaction>> localTranscactions = (ThreadLocal<List<Transaction>>) transactions.get(datasourceName);
		if (localTranscactions != null) {
			List<Transaction> trxs = (List<Transaction>) localTranscactions.get();
			return (trxs != null) && (trxs.size() > 0);
		}
		return false;
	}

	public static boolean isTopTransaction(String datasourceName, Transaction transaction) {
		List<Transaction> trxs = getTransactions(datasourceName);
		boolean f = false;
		if (trxs != null) {
			int num = 0;
			for (Transaction tran : trxs) {
				if (tran.getPropagation() != 2) {
					num++;
					if ((num == 1) && (tran.equals(transaction))) {
						f = true;
						break;
					}
					if (num > 1) {
						break;
					}
				}
			}
		}
		return f;
	}

	public static List<Transaction> getTransactions(String datasourceName) {
		ThreadLocal<List<Transaction>> localTranscactions = (ThreadLocal<List<Transaction>>) transactions.get(datasourceName);
		if (localTranscactions != null) {
			return (List<Transaction>) localTranscactions.get();
		}
		return null;
	}

	public static Transaction getLastTransaction(String datasourceName) {
		ThreadLocal<List<Transaction>> localTranscactions = (ThreadLocal<List<Transaction>>) transactions.get(datasourceName);
		if (localTranscactions != null) {
			List<Transaction> trxs = (List<Transaction>) localTranscactions.get();
			if (trxs == null)
				return null;
			if (trxs.size() > 0)
				return (Transaction) trxs.get(trxs.size() - 1);
		}
		return null;
	}

	public static Transaction getFirstTransaction(String datasourceName) {
		ThreadLocal<List<Transaction>> localTranscactions = (ThreadLocal<List<Transaction>>) transactions.get(datasourceName);
		if (localTranscactions != null) {
			List<Transaction> trxs = (List<Transaction>) localTranscactions.get();
			if (trxs == null)
				return null;
			if (trxs.size() > 0) {
				return (Transaction) trxs.get(0);
			}
		}
		return null;
	}

	public static void addSavepoint(String datasourceName, Savepoint savepoint) {
		ThreadLocal<List<Savepoint>> localSavepoints = (ThreadLocal<List<Savepoint>>) savepoints.get(datasourceName);
		if (localSavepoints != null) {
			List<Savepoint> trxs = (List<Savepoint>) localSavepoints.get();
			if (trxs == null) {
				trxs = new ArrayList<Savepoint>();
				localSavepoints.set(trxs);
			}
			trxs.add(savepoint);
		}
	}

	public static void removeSavepoint(String datasourceName, Savepoint savepoint) {
		ThreadLocal<List<Savepoint>> localSavepoints = (ThreadLocal<List<Savepoint>>) savepoints.get(datasourceName);
		if (localSavepoints != null) {
			List<Savepoint> trxs = (List<Savepoint>) localSavepoints.get();
			if (trxs == null)
				return;
			trxs.remove(savepoint);
		}
	}

	public static void removeAllSavepoint(String datasourceName) {
		ThreadLocal<List<Savepoint>> localSavepoints = (ThreadLocal<List<Savepoint>>) savepoints.get(datasourceName);
		if (localSavepoints != null) {
			List<Savepoint> trxs = (List<Savepoint>) localSavepoints.get();
			if (trxs == null)
				return;
			trxs.clear();
		}
	}

	public static Savepoint getLastSavepoint(String datasourceName) {
		ThreadLocal<List<Savepoint>> localSavepoints = (ThreadLocal<List<Savepoint>>) savepoints.get(datasourceName);
		if (localSavepoints != null) {
			List<Savepoint> trxs = (List<Savepoint>) localSavepoints.get();
			if (trxs == null)
				return null;
			if (trxs.size() > 0)
				return (Savepoint) trxs.get(trxs.size() - 1);
		}
		return null;
	}

	public static void getStatus(String datasourceName) {
		List<Transaction> t = getTransactions(datasourceName);
		System.out.println("t:" + (t == null ? "null" : Integer.valueOf(t.size())));

		Connection c = getConnectionResource(datasourceName);
		System.out.println("c:" + (c == null ? "null" : c));

		ThreadLocal<List<Savepoint>> localSavepoints = (ThreadLocal<List<Savepoint>>) savepoints.get(datasourceName);
		List<Savepoint> s = null;
		if (localSavepoints != null) {
			s = (List<Savepoint>) localSavepoints.get();
		}
		System.out.println("s:" + (s == null ? "null" : Integer.valueOf(s.size())));
	}
}